package com.chesnutconsulting.otbasket.image.watermark;

import com.chesnutconsulting.otbasket.image.finder.artesia.OtBasketConfiguration;
import com.chesnutconsulting.otbasket.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * User: kandhari
 * Date: 2/17/13 1:34 PM
 * <p/>
 * Document me
 */
@org.springframework.stereotype.Component
public class WatermarkedImageCreator {
    private static final Logger LOGGER = LoggerFactory.getLogger(WatermarkedImageCreator.class);

    private final String watermarkFilePath;

    private final String outputPath;

    
    public WatermarkedImageCreator(OtBasketConfiguration otBasketConfig)
    {
    	this.outputPath = otBasketConfig.getOutputPath();
    	this.watermarkFilePath = otBasketConfig.getWatermarkFilePath();
    }
    
    /**
     * @param imagesToWatermark create watermark
     * @return the location where watermarked files were outputted
     */
    public List<File> watermark(List<File> imagesToWatermark) {
        String outputSubDir = UUID.randomUUID().toString();
        List<File> wmFiles = new ArrayList<File>();
        for(File toWatermark : imagesToWatermark) {
            wmFiles.add(watermark(toWatermark, outputSubDir));
        }

//        return (OUTPUT_PATH + outputSubDir);
        return wmFiles;
    }

    /**
     * @param onImage create watermark
     * @param outputSubDirectory
     * @return watermarked File
     */
    public File watermark(File onImage, String outputSubDirectory) {
        String outputDir = outputPath + outputSubDirectory + "/";
        prepareOutputDirectory(outputDir);
        String filePath = outputDir + onImage.getName();
        File copiedFile = FileUtil.copy(filePath, onImage);

        BufferedImage watermarked = addWatermark(readImage(filePath));
        writeImageToDisc(watermarked, copiedFile);
        return copiedFile;
    }

    private void writeImageToDisc(BufferedImage image, File whereToWrite) {
        String error = String.format("Error writing image to path=%s", whereToWrite.getPath());
        try {
            if(!ImageIO.write(image, "jpg", whereToWrite)) {
                LOGGER.error(error);
                throw new AssertionError(error);
            }
        } catch (IOException ioe)  {
            LOGGER.error(error);
            throw new AssertionError(error);
        }
    }

    /**
     * @return the watermark
     */
    BufferedImage getWatermark() {
        return readImage(watermarkFilePath);
    }

    /**
     * @param filePath of image
     * @return
     */
    BufferedImage readImage(String filePath) {
        try {
            return ImageIO.read(new File(filePath));
        } catch (IOException ioe) {
            LOGGER.error(String.format("Error finding image at path=%s", filePath), ioe);
            throw new AssertionError(String.format("Error finding image at path=%s", filePath));
        }
    }

    /**
     * @param onImage image to watermark
     * @return watermarked {@link BufferedImage}
     */
    BufferedImage addWatermark(BufferedImage onImage) {
        BufferedImage watermark = getWatermark();
        Coordinates coordinates = new XYBuilder()
                .setWidth(onImage.getWidth())
                .setHeight(onImage.getHeight())
                .setWatermarkWidth(watermark.getWidth())
                .setWatermarkHeight(watermark.getHeight())
                .toCoordinates();

        Graphics2D graphicsToWatermark = (Graphics2D) onImage.getGraphics();
        AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
        graphicsToWatermark.setComposite(alpha);
        graphicsToWatermark.drawImage(watermark, coordinates.x, coordinates.y, null);
        graphicsToWatermark.dispose();

        return onImage;
    }

    public File prepareOutputDirectory(String outputDirectoryPath) {
        File outputHere = new File(outputDirectoryPath);
        if(!outputHere.exists()) {
            outputHere.mkdirs();
        }

        return outputHere;
    }

    /**
     * Provides x, y coordinates for watermark placement.
     */
    private static class Coordinates {
        private final int x, y;

        Coordinates(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    /**
     * Determines {@link Coordinates} given image and watermark width and height.
     */
    private static class XYBuilder {
        private int imageWidth, imageHeight, watermarkWidth, watermarkHeight;

        private XYBuilder setWidth(int width) {
            this.imageWidth = width;
            return this;
        }

        private XYBuilder setHeight(int height) {
            this.imageHeight = height;
            return this;
        }

        private XYBuilder setWatermarkWidth(int width) {
            this.watermarkWidth = width;
            return this;
        }

        private XYBuilder setWatermarkHeight(int height) {
            this.watermarkHeight = height;
            return this;
        }

        private Coordinates toCoordinates() {
            return new Coordinates(
                    (imageWidth - watermarkWidth) / 2,
                    (imageHeight - watermarkHeight) / 2
            );
        }
    }
}
